package redis_ser

import (
	"5title_gin/global"
	"context"
	"errors"
	"fmt"
	"github.com/redis/go-redis/v9"
	"time"
)

// CheckLock 检查用户是否被锁定
func CheckLock(username string) (bool, error) {
	key := fmt.Sprintf("lock:%s", username)
	lock, err := global.Redis.Get(context.Background(), key).Result()
	if err != nil {
		if errors.Is(err, redis.Nil) {
			return false, nil
		}
		return false, err
	}
	return lock == "1", nil
}

// IncrementFailedAttempts 增加失败次数
func IncrementFailedAttempts(username string) (int, int, error) {
	// 定义 Redis key
	attemptsKey := fmt.Sprintf("attempts:%s", username)
	lockKey := fmt.Sprintf("lock:%s", username)

	// 获取配置
	userConfig := global.Config.User
	maxAttempts := userConfig.Password.MaxRetryCount

	// 解析锁定时间
	lockDuration, err := time.ParseDuration(userConfig.Password.LockTime)
	if err != nil {
		return 0, 0, fmt.Errorf("invalid lock duration: %v", err)
	}

	// 使用 Redis 事务确保原子性
	var result int64
	err = global.Redis.Watch(context.Background(), func(tx *redis.Tx) error {
		// 获取当前失败次数
		current, err := tx.Get(context.Background(), attemptsKey).Int64()
		if err != nil && !errors.Is(err, redis.Nil) {
			return err
		}

		// Pipeline 操作
		pipe := tx.TxPipeline()

		// 增加失败计数
		incr := pipe.Incr(context.Background(), attemptsKey)

		// 如果是第一次失败，设置过期时间
		if current == 0 {
			pipe.Expire(context.Background(), attemptsKey, lockDuration)
		}

		// 执行 Pipeline
		_, err = pipe.Exec(context.Background())
		if err != nil {
			return err
		}

		result = incr.Val()

		// 如果超过最大尝试次数，设置锁定
		if result >= int64(maxAttempts) {
			_, err = tx.Set(context.Background(), lockKey, "1", lockDuration).Result()
			if err != nil {
				return err
			}
		}

		return nil
	}, attemptsKey, lockKey)

	if err != nil {
		return 0, 0, fmt.Errorf("redis transaction failed: %v", err)
	}
	_maxAttempts := int(maxAttempts)
	return int(result), _maxAttempts, nil
}

// ClearFailedAttempts 清除失败记录
func ClearFailedAttempts(username string) error {
	_, err := global.Redis.Del(context.Background(), fmt.Sprintf("attempts:%s", username)).Result()
	if err != nil {
		return err
	}
	_, err = global.Redis.Del(context.Background(), fmt.Sprintf("lock:%s", username)).Result()
	return err
}
